package com.example.base_model.network.download

import android.content.ContentValues
import android.content.Context
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.MediaStore
import com.blankj.utilcode.util.LogUtils
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.yield
import okhttp3.OkHttpClient
import okhttp3.ResponseBody
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.http.GET
import retrofit2.http.Streaming
import retrofit2.http.Url
import java.io.File
import java.io.FileOutputStream
import java.io.OutputStream
import javax.inject.Inject

/**
 * @Author jiangKunKun
 * @CreateDate 2025/8/27
 * @Description
 * 文件下载管理器
 * 提供基于 Retrofit 和协程的文件下载功能，支持下载进度监听
 * @param okHttpClient 用于网络请求的 OkHttpClient 实例
 * @param retrofit 用于创建 API 接口的 Retrofit 实例
 * @SpittingGrooves
 */
class DownloadManager @Inject constructor(
    private val okHttpClient: OkHttpClient,
    private val retrofit: Retrofit,
    @ApplicationContext private val context: Context
) {

    private val downloadApi by lazy {
        retrofit.newBuilder()
            .client(okHttpClient.newBuilder().build())
            .build()
            .create(DownloadApi::class.java)
    }

    interface DownloadApi {
        @Streaming
        @GET
        suspend fun downloadFile(@Url url: String): Response<ResponseBody>
    }

    sealed class DownloadStatus {
        object IDLE : DownloadStatus()
        object Started : DownloadStatus()
        data class Progress(val progress: Int) : DownloadStatus()
        data class Success(val fileUri: Uri, val filePath: String?) : DownloadStatus() // 返回Uri和可选的路径
        data class Failed(val error: String) : DownloadStatus()
        object Finished : DownloadStatus()
    }

    /**
     * 下载文件并保存。
     * @param downloadUrl 文件的下载地址。
     * @param destinationDirName 公共目录中的目标子文件夹名称 (例如 "MyAppDownloads", "Wallpapers")。
     *                           对于 Android Q+，这会成为 MediaStore 中 RELATIVE_PATH 的一部分。
     *                           对于 Android P-，这会是 Environment.DIRECTORY_PICTURES 下的子文件夹。
     * @param fileName 要保存的文件名 (例如 "image.jpg")。
     */
    fun downloadFile(
        downloadUrl: String,
        destinationDirName: String, // 例如 "MyAppName/Images" 或直接 "MyImages"
        fileName: String
    ): Flow<DownloadStatus> = flow {
        emit(DownloadStatus.Started)
        var outputStream: OutputStream? = null
        var fileUriForResult: Uri? = null
        var filePathForResult: String? = null

        try {
            val response = downloadApi.downloadFile(downloadUrl)

            if (response.isSuccessful) {
                response.body()?.let { body ->
                    val resolver = context.contentResolver
                    val mimeType = getMimeTypeFromFileName(fileName)

                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                        // Android Q (API 29) 及以上版本，使用 MediaStore
                        val contentValues = ContentValues().apply {
                            put(MediaStore.MediaColumns.DISPLAY_NAME, fileName)
                            put(MediaStore.MediaColumns.MIME_TYPE, mimeType)
                            put(
                                MediaStore.MediaColumns.RELATIVE_PATH,
                                Environment.DIRECTORY_PICTURES + File.separator + destinationDirName
                            )
                            put(MediaStore.MediaColumns.IS_PENDING, 1) // 文件正在写入时标记为待处理
                        }

                        val collection = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
                        val imageUri = resolver.insert(collection, contentValues)

                        if (imageUri == null) {
                            emit(DownloadStatus.Failed("Failed to create MediaStore entry."))
                            return@flow
                        }
                        fileUriForResult = imageUri
                        outputStream = resolver.openOutputStream(imageUri)

                        if (outputStream == null) {
                            emit(DownloadStatus.Failed("Failed to get output stream from MediaStore URI."))
                            // 尝试删除未完成的条目
                            resolver.delete(imageUri, null, null)
                            return@flow
                        }
                    } else {
                        // Android P (API 28) 及以下版本，直接写入文件系统
                        // 需要 WRITE_EXTERNAL_STORAGE 权限
                        val publicPicturesDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
                        val targetDir = File(publicPicturesDir, destinationDirName)
                        if (!targetDir.exists()) {
                            targetDir.mkdirs()
                        }
                        val file = File(targetDir, fileName)
                        filePathForResult = file.absolutePath
                        fileUriForResult = Uri.fromFile(file) // 为旧版本也生成一个Uri
                        outputStream = FileOutputStream(file)
                    }

                    // --- 通用的文件写入逻辑 ---
                    val inputStream = body.byteStream()
                    val fileSize = body.contentLength()
                    var downloaded = 0L
                    val buffer = ByteArray(8192) // 8KB buffer
                    var bytesRead: Int

                    emit(DownloadStatus.Progress(0))
                    var lastProgress = 0

                    while (inputStream.read(buffer).also { bytesRead = it } != -1) {
                        outputStream?.write(buffer, 0, bytesRead)
                        downloaded += bytesRead

                        if (fileSize > 0) {
                            val progress = ((downloaded * 100) / fileSize).toInt()
                            if (progress != lastProgress) {
                                emit(DownloadStatus.Progress(progress))
                                lastProgress = progress
                            }
                        }
                        yield() // 允许协程切换
                    }
                    outputStream?.flush()

                    if (lastProgress != 100 && fileSize > 0) {
                        emit(DownloadStatus.Progress(100))
                    }

                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && fileUriForResult != null) {
                        // 对于 MediaStore，在写入完成后更新 IS_PENDING 状态
                        val updateDetails = ContentValues().apply {
                            put(MediaStore.MediaColumns.IS_PENDING, 0)
                        }
                        resolver.update(fileUriForResult!!, updateDetails, null, null)
                    }

                    emit(DownloadStatus.Success(fileUriForResult!!, filePathForResult))

                    // 关闭流
                    inputStream.close()
                    outputStream?.close() // outputStream 可能为null，如果早期失败

                } ?: run {
                    emit(DownloadStatus.Failed("Response body is null"))
                }
            } else {
                emit(DownloadStatus.Failed("HTTP ${response.code()}: ${response.message()}"))
            }
        } catch (e: Exception) {
            LogUtils.d("DownloadManager", "Download failed: ${e.message}", e)
            emit(DownloadStatus.Failed(e.message ?: "Download failed due to an exception"))
            // 如果是MediaStore且有Uri，尝试删除未完成的条目
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && fileUriForResult != null && outputStream != null) {
                try {
                    context.contentResolver.delete(fileUriForResult!!, null, null)
                } catch (deleteEx: Exception) {
                    LogUtils.d("DownloadManager", "Failed to delete pending MediaStore entry: ${deleteEx.message}")
                }
            }
        } finally {
            try {
                outputStream?.close() // 确保在 finally 中也尝试关闭
            } catch (ioe: Exception) {
                LogUtils.d("DownloadManager", "Error closing outputStream in finally: ${ioe.message}")
            }
            emit(DownloadStatus.Finished)
        }
    }.flowOn(Dispatchers.IO)

    private fun getMimeTypeFromFileName(fileName: String): String {
        val extension = fileName.substringAfterLast('.', "").lowercase()
        return when (extension) {
            "jpg", "jpeg" -> "image/jpeg"
            "png" -> "image/png"
            "gif" -> "image/gif"
            "webp" -> "image/webp"
            "bmp" -> "image/bmp"
            "mp4" -> "video/mp4"
            "pdf" -> "application/pdf"
            // 添加更多MIME类型
            else -> "application/octet-stream" // 通用二进制流
        }
    }
}